package cn.sh.yhk.acl.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.sh.yhk.acl.mapper.*;
import cn.sh.yhk.acl.po.*;
import cn.sh.yhk.acl.vo.UserInfoPageVo;
import cn.sh.yhk.acl.vo.UserInfoVo;
import cn.sh.yhk.base.vo.BaseResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UserInfoServiceImpl implements UserInfoService {

    @Autowired
    UserMapper userMapper;
    @Autowired
    RoleMapper roleMapper;
    @Autowired
    UserRoleMapper userRoleMapper;
    @Autowired
    RolePermissionMapper rolePermissionMapper;
    @Autowired
    PermissionMapper permissionMapper;
    @Autowired
    TokenCacheMapper tokenCacheMapper;
    @Autowired
    PermissionService permissionService;

    @Transactional
    @Override
    public IPage<UserInfoVo> selectUserInfoPage(UserInfoPageVo userInfoPageVo) {
        LambdaQueryWrapper<UserPo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.hasText(userInfoPageVo.getUsername()))
            lambdaQueryWrapper.eq(UserPo::getUsername, userInfoPageVo.getUsername());
        IPage<UserPo> iPage = new Page<>(userInfoPageVo.getPage(), userInfoPageVo.getPageSize());
        iPage = userMapper.selectPage(iPage, lambdaQueryWrapper);
        IPage<UserInfoVo> result = iPage.convert(po -> {
            UserInfoVo userInfoVo = new UserInfoVo();
            BeanUtils.copyProperties(po, userInfoVo);
            TokenCachePo cachePo = tokenCacheMapper.selectOne(new LambdaQueryWrapper<TokenCachePo>()
                    .eq(TokenCachePo::getUsername, userInfoVo.getUsername()));
            if (!ObjectUtils.isEmpty(cachePo)) {
                userInfoVo.setLastOperationTime(Date.from(cachePo.getLastOperationDate()
                        .atZone(ZoneId.systemDefault()).toInstant()));
            }
            userInfoVo.setRoleList(permissionService.selectRoleList(po.getId()));
            return userInfoVo;
        });
        return result;
    }

    @Override
    public Integer register(UserInfoVo userInfoVo) {
        UserPo userPo = new UserPo();
        BeanUtils.copyProperties(userInfoVo, userPo);
        //TODO 密码加密
        return userMapper.insert(userPo);
    }

    public Integer addUser(UserInfoVo vo) {
        UserPo userPo = new UserPo();
        BeanUtil.copyProperties(vo, userPo);
        return userMapper.insert(userPo);
    }

    @Override
    public Integer delUser(Integer userId) {
        return userMapper.deleteById(userId);
    }

    @Override
    public Integer updateUser(UserInfoVo userInfoVo) {
        UserPo userPo = new UserPo();
        BeanUtil.copyProperties(userInfoVo, userPo);
        return userMapper.updateById(userPo);
    }

    @Override
    public UserPo selectUserByUserId(Integer userId) {
        return userMapper.selectById(userId);
    }

    //demo不想再开个redis了
    @Cacheable(value = "users", key = "#username")
    @Override
    public UserInfoVo selectUserByUserName(String username) {
        UserPo po = userMapper.selectOne(new LambdaQueryWrapper<UserPo>().eq(UserPo::getUsername, username));
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtil.copyProperties(po, userInfoVo);
        return userInfoVo;
    }

    @Override
    public UserInfoVo selectUserWithRoleById(Integer userId) {
        UserPo user = userMapper.selectById(userId);
        if (!ObjectUtils.isEmpty(user)) {
            UserInfoVo userInfoVo = new UserInfoVo();
            BeanUtils.copyProperties(user, userInfoVo);
            List<UserRolePo> userRolePoList = userRoleMapper.selectList(new LambdaQueryWrapper<UserRolePo>().eq(UserRolePo::getUid, userId));
            List<RolePo> roles = roleMapper.selectBatchIds(userRolePoList.stream().map(UserRolePo::getRid).collect(Collectors.toList()));
            userInfoVo.setRoleList(roles);
            return userInfoVo;
        }
        return null;
    }

    @Override
    public Integer updateUserPassword(Integer userId, String password) {
        return null;
    }

    @Override
    public List<RolePo> selectRoleByUserId(Integer userId) {
        List<Integer> roleIds = userRoleMapper.selectList(new LambdaQueryWrapper<UserRolePo>().eq(UserRolePo::getUid, userId))
                .stream().map(UserRolePo::getRid).toList();
        return roleMapper.selectBatchIds(roleIds);
    }

    @Override
    public Boolean lockUser(Integer userId) {
        UserPo user = new UserPo();
        user.setEnabled(false);
        user.setId(userId);
        return userMapper.updateById(user) > 0;
    }

    //role or permission
    @Override
    public Integer addRole(RolePo rolePo) {
        long count = roleMapper.selectCount(new LambdaQueryWrapper<RolePo>().eq(RolePo::getName, rolePo.getName()));
        if (count != 0) {
            return 0;
        }
        return roleMapper.insert(rolePo);
    }

    @Override
    public Integer updateRole(RolePo rolePo) {
        return roleMapper.updateById(rolePo);
    }

    @Override
    public Integer delRole(Integer id) {
        return roleMapper.deleteById(id);
    }

    @Override
    public RolePo getRoleById(Integer id) {
        return null;
    }

    @Override
    public List<RolePo> getRoleList() {
        return List.of();
    }

    @Override
    public Integer addPermission(PermissionPo permissionPo) {
        return permissionMapper.insert(permissionPo);
    }

    @Override
    public Integer updatePermission(PermissionPo permissionPo) {
        return permissionMapper.updateById(permissionPo);
    }

    @Override
    public Integer delPermission(Integer id) {
        return permissionMapper.deleteById(id);
    }

//    @Override
//    public Map<String, List<PermissionPo>> getPermissionListByRoleId(Integer RoleId) {
//        List<Integer> permissionIds = rolePermissionMapper.selectList(new LambdaQueryWrapper<RolePermissionPo>().eq(RolePermissionPo::getRid, RoleId))
//                .stream().map(RolePermissionPo::getPid).toList();
//        return permissionMapper.selectBatchIds(permissionIds).stream()
//                .filter(permissionPo -> permissionPo.getIsMenu() == 1 && permissionPo.getParentId() == 0)
//                .collect(Collectors.groupingBy(PermissionPo::getMenuName, Collectors.mapping(p -> p, Collectors.toList())));
//    }
}
